package com.example.his.api.front.service.impl;

import cn.hutool.core.map.MapUtil;
import com.example.his.api.common.PageUtils;
import com.example.his.api.db.dao.AppointmentDao;
import com.example.his.api.db.dao.AppointmentRestrictionDao;
import com.example.his.api.db.dao.OrderDao;
import com.example.his.api.db.pojo.AppointmentEntiy;
import com.example.his.api.front.service.AppointmentService;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("FrontAppointmentService")
public class AppointmentServiceImpl implements AppointmentService {
  
  @Resource
  private AppointmentDao appointmentDao;
  
  @Resource
  private AppointmentRestrictionDao appointmentRestrictionDao;
  
  @Resource
  private OrderDao orderDao;
  
  @Resource
  private RedisTemplate redisTemplate;
  
  
  @Override
  @Transactional
  public String insert(AppointmentEntiy appointmentEntiy) {
    HashMap <String, String> resultCode = new HashMap() {{
      put("full", "当天预约已满，请选择其他日期");
      put("fail", "预约失败");
      put("success", "预约成功");
    }};
    String key = "appointment#" + appointmentEntiy.getDate();
    String execute = (String)redisTemplate.execute(new SessionCallback() {
      
      @Override
      public String execute(RedisOperations operations) throws DataAccessException {
        //        关注缓存数据，拿到乐观锁version
        operations.watch(key);
        //        拿到缓存的数据
        Map entries = operations.opsForHash().entries(key);
        int maxNum = Integer.parseInt(entries.get("maxNum").toString());
        Integer realNum = Integer.parseInt(entries.get("realNum").toString());
        if(realNum < maxNum) {
          //  开启redis事务
          operations.multi();
          //          已预约人数+1
          operations.opsForHash().increment(key, "realNum", 1);
          //          提交事务
          List <Boolean> list = operations.exec();
          
          if(list.size() == 0) {
            return resultCode.get("fail");
          } else {
            return resultCode.get("success");
          }
          //          return resultCode.get(bool ? "success" : "fail");
        } else {
          operations.unwatch();
          return resultCode.get("full");
        }
      }
    });
    
    //    如果redis事务提交失败就结束service的方法
    if(! execute.equals(resultCode.get("success"))) {
      return execute;
    }
    
    int rows = appointmentDao.insert(appointmentEntiy);
    if(rows != 1) {
      return resultCode.get("fail");
    }
    
    Map entries = redisTemplate.opsForHash().entries(key);
    int maxNum = Integer.parseInt(entries.get("maxNum").toString());
    HashMap param = new HashMap() {{
      put("date", appointmentEntiy.getDate());
      put("num_1", maxNum);
      put("num_2", maxNum);
      put("num_3", 1);
    }};
    
    //    更新预约现流表中的预约人数
    int i = appointmentRestrictionDao.saveOrUpdateRealNum(param);
    if(i == 0) {
      return resultCode.get("fail");
    }
    
    //    更新订单状态
    Integer orderId = appointmentEntiy.getOrderId();
    param = new HashMap <>() {{
      put("id", orderId);
      put("status", 5);
    }};
    
    int i1 = orderDao.updateStatus(param);
    if(i1 == 0) {
      return resultCode.get("fail");
    }
    
    return resultCode.get("success");
    
  }
  
  @Override
  public PageUtils searchByPage(Map param) {
    ArrayList list = new ArrayList();
    long count = appointmentDao.searchFrontAppointmentCount(param);
    if (count>0) {
      list = appointmentDao.searchFrontAppointmentByPage(param);
    }
    int page = MapUtil.getInt(param, "page");
    int length = MapUtil.getInt(param, "length");
    PageUtils pageUtils = new PageUtils(list, count, page, length);
    return pageUtils;
  }
}
